<template>
  <view v-if="isShow" ref="ani" class="uni-transition" :class="[ani.in]" :style="'transform:' +transform+';'+stylesObject" @click="change">
    <slot />
  </view>
</template>

<script>
	// #ifdef APP-NVUE
  const animation = uni.requireNativePlugin('animation');
  // #endif
  /**
   * Transition 过渡动画
   * @description 简单过渡动画组件
   * @tutorial https://ext.dcloud.net.cn/plugin?id=985
   * @property {Boolean} show = [false|true] 控制组件显示或隐藏
   * @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
   *  @value fade 渐隐渐出过渡
   *  @value slide-top 由上至下过渡
   *  @value slide-right 由右至左过渡
   *  @value slide-bottom 由下至上过渡
   *  @value slide-left 由左至右过渡
   *  @value zoom-in 由小到大过渡
   *  @value zoom-out 由大到小过渡
   * @property {Number} duration 过渡动画持续时间
   * @property {Object} styles 组件样式，同 css 样式，注意带’-‘连接符的属性需要使用小驼峰写法如：`backgroundColor:red`
   */
  export default {
    name:	'UniTransition',
    props: {
      show: {
        type: Boolean,
        default: false
      },
      modeClass: {
        type: Array,
        default() {
          return []
        }
      },
      duration: {
        type: Number,
        default: 300
      },
      styles: {
        type: Object,
        default() {
          return {}
        }
      }
    },
    data() {
      return {
        isShow: false,
        transform: '',
        ani: {
          in: '',
          active: ''
        }
      };
    },
    computed: {
      stylesObject() {
        let styles = {
					...this.styles,
					'transition-duration': this.duration / 1000 + 's'
        }
        let transfrom = ''
        for (let i in styles) {
          let line = this.toLine(i)
          transfrom += line + ':' + styles[i] + ';'
        }
        return transfrom
      }
    },
    watch: {
      show: {
        handler(newVal) {
          if (newVal) {
            this.open()
          } else {
            this.close()
          }
        },
        immediate: true
      }
    },
    created() {
      // this.timer = null
      // this.nextTick = (time = 50) => new Promise(resolve => {
      // 	clearTimeout(this.timer)
      // 	this.timer = setTimeout(resolve, time)
      // 	return this.timer
      // });
    },
    methods: {
      change() {
        this.$emit('click', {
          detail: this.isShow
        })
      },
      open() {
        clearTimeout(this.timer)
        this.isShow = true
        this.transform = ''
        this.ani.in = ''
        for (let i in this.getTranfrom(false)) {
          if (i === 'opacity') {
            this.ani.in = 'fade-in'
          } else {
            this.transform += `${this.getTranfrom(false)[i]} `
          }
        }
        this.$nextTick(() => {
          setTimeout(() => {
            this._animation(true)
          }, 50)
        })
      },
      close(type) {
        clearTimeout(this.timer)
        this._animation(false)
      },
      _animation(type) {
        let styles = this.getTranfrom(type)
        // #ifdef APP-NVUE
        if (!this.$refs['ani']) return
        animation.transition(this.$refs['ani'].ref, {
          styles,
          duration: this.duration, // ms
          timingFunction: 'ease',
          needLayout: false,
          delay: 0 // ms
        }, () => {
          if (!type) {
            this.isShow = false
          }
          this.$emit('change', {
            detail: this.isShow
          })
        })
        // #endif
        // #ifndef APP-NVUE
        this.transform = ''
        for (let i in styles) {
          if (i === 'opacity') {
            this.ani.in = `fade-${type ? 'out' : 'in'}`
          } else {
            this.transform += `${styles[i]} `
          }
        }
        this.timer = setTimeout(() => {
          if (!type) {
            this.isShow = false
          }
          this.$emit('change', {
            detail: this.isShow
          })
        }, this.duration)
        // #endif
      },
      getTranfrom(type) {
        let styles = {
          transform: ''
        }
        this.modeClass.forEach((mode) => {
          switch (mode) {
          case 'fade':
            styles.opacity = type ? 1 : 0
            break;
          case 'slide-top':
            styles.transform += `translateY(${type ? '0' : '-100%'}) `
            break;
          case 'slide-right':
            styles.transform += `translateX(${type ? '0' : '100%'}) `
            break;
          case 'slide-bottom':
            styles.transform += `translateY(${type ? '0' : '100%'}) `
            break;
          case 'slide-left':
            styles.transform += `translateX(${type ? '0' : '-100%'}) `
            break;
          case 'zoom-in':
            styles.transform += `scale(${type ? 1 : 0.8}) `
            break;
          case 'zoom-out':
            styles.transform += `scale(${type ? 1 : 1.2}) `
            break;
          }
        })
        return styles
      },
      _modeClassArr(type) {
        let mode = this.modeClass
        if (typeof (mode) !== 'string') {
          let modestr = ''
          mode.forEach((item) => {
            modestr += (item + '-' + type + ',')
          })
          return modestr.substr(0, modestr.length - 1)
        } else {
          return mode + '-' + type
        }
      },
      // getEl(el) {
      // 	console.log(el || el.ref || null);
      // 	return el || el.ref || null
      // },
      toLine(name) {
        return name.replace(/([A-Z])/g, '-$1').toLowerCase();
      }
    }
  }
</script>

<style scoped>
	.uni-transition {
		transition-timing-function: ease;
		transition-duration: 0.3s;
		transition-property: transform, opacity;
	}

	.fade-in {
		opacity: 0;
	}

	.fade-active {
		opacity: 1;
	}

	.slide-top-in {
		/* transition-property: transform, opacity; */
		transform: translateY(-100%);
	}

	.slide-top-active {
		transform: translateY(0);
		/* opacity: 1; */
	}

	.slide-right-in {
		transform: translateX(100%);
	}

	.slide-right-active {
		transform: translateX(0);
	}

	.slide-bottom-in {
		transform: translateY(100%);
	}

	.slide-bottom-active {
		transform: translateY(0);
	}

	.slide-left-in {
		transform: translateX(-100%);
	}

	.slide-left-active {
		transform: translateX(0);
		opacity: 1;
	}

	.zoom-in-in {
		transform: scale(0.8);
	}

	.zoom-out-active {
		transform: scale(1);
	}

	.zoom-out-in {
		transform: scale(1.2);
	}
</style>